<?php
/**
 * | ---------------------------------------------------------------------------------------------------
 * | Author：johnxu <fsyzxz@163.com>.
 * | ---------------------------------------------------------------------------------------------------
 * | Home: https://www.johnxu.net.
 * | ---------------------------------------------------------------------------------------------------
 * | Data: 2019-03-18
 * | ---------------------------------------------------------------------------------------------------
 * | Desc:
 * | ---------------------------------------------------------------------------------------------------
 */

namespace app\service\websocket\handler;

use johnxu\tool\Restful;
use think\Db;

abstract class Driver extends Restful
{

    protected $from;

    protected $to;

    protected $data;

    /**
     * @var \swoole_websocket_server
     */
    protected $server;

    public function __construct( $data )
    {
        $this->data = $data['data'] ?? [];
    }

    abstract protected function getType();

    /**
     * 发送消息
     *
     * @param \swoole_websocket_server $server
     */
    public function handler( \swoole_websocket_server $server, $fd )
    {
        $this->server      = $server;
        $this->to['fd']    = $fd;
        $this->from['fd']  = $fd;
        $this->data['uid'] = $this->data['uid'] ?? mb_strcut( md5( $server->getClientInfo( $fd )['remote_ip'] ), 0, 16 );

        if ( $server->exist( $this->getToInfo()['fd'] ) && $this->intercept( $server, $fd ) )
        {
            $data = is_array( $this->getData() ) ? $this->jsonEncode( $this->getData() ) : $this->getData();
            $server->push( $this->getToInfo()['fd'], $data );
        }
    }

    /**
     * 拦截器（如需要自行推送内容，请在这里处理）
     *
     * @param \swoole_websocket_server $server
     * @param                          $fd
     *
     * @return bool
     */
    protected function intercept( \swoole_websocket_server $server, $fd )
    {
        return true;
    }

    /**
     * 获取发送者信息
     *
     * @return mixed
     */
    protected function getFromInfo()
    {
        return $this->from;
    }

    /**
     * 获取接收者信息
     *
     * @return mixed
     */
    protected function getToInfo()
    {
        return $this->to;
    }

    /**
     * 获取数据
     *
     * @return mixed
     */
    protected function getData()
    {
        return $this->data;
    }

    /**
     * 获取当前时间
     *
     * @return false|string
     */
    protected function getTime()
    {
        return date( 'Y-m-d H:i:s' );
    }

    /**
     * 数组转换成json字符串
     *
     * @param array $data
     *
     * @return false|string
     */
    protected function jsonEncode( array $data )
    {
        if ( !isset( $data['type'] ) )
        {
            $data = [
                'type' => $this->getType(),
                'data' => $data
            ];
        }

        return json_encode(
            $data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
        );
    }

    /**
     * json字符串转换成数组
     *
     * @param string $data
     *
     * @return mixed
     */
    protected function jsonDecode( string $data )
    {
        return json_decode( $data, true );
    }

    /**
     * Get user infomation
     *
     * @param array $where
     *
     * @return array|\PDOStatement|string|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function getUser( array $where )
    {
        return Db::name( 'users' )->where( $where )->find();
    }

    protected function updateUser( array $data, array $where )
    {
        Db::name( 'users' )->where( $where )->update( $data );
    }

    /**
     * Get token infomation
     *
     * @param string $token
     *
     * @return array|\PDOStatement|string|\think\Model|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function getTokenInfo( string $token )
    {
        return Db::name( 'token' )->where( [ 'token' => $this->data['token'], 'status' => 1 ] )->find();
    }
}